package com.zzyl.nursing.service.impl;

import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.*;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.github.pagehelper.PageHelper;
import com.huaweicloud.sdk.iotda.v5.IoTDAClient;
import com.huaweicloud.sdk.iotda.v5.model.ServiceCapability;
import com.huaweicloud.sdk.iotda.v5.model.ServiceProperty;
import com.huaweicloud.sdk.iotda.v5.model.ShowProductRequest;
import com.huaweicloud.sdk.iotda.v5.model.ShowProductResponse;
import com.zzyl.common.constant.Constants;
import com.zzyl.common.utils.StringUtils;
import com.zzyl.common.utils.UserThreadLocal;
import com.zzyl.framework.web.service.TokenService;
import com.zzyl.nursing.domain.*;
import com.zzyl.nursing.dto.BindElderDto;
import com.zzyl.nursing.dto.QueryDeviceDataDto;
import com.zzyl.nursing.dto.QueryDevicePropertyStatusDto;
import com.zzyl.nursing.dto.UserLoginRequestDto;
import com.zzyl.nursing.mapper.DeviceDataMapper;
import com.zzyl.nursing.service.*;
import com.zzyl.nursing.vo.*;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.annotations.Select;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import com.zzyl.nursing.mapper.FamilyMemberMapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;

/**
 * 老人家属Service业务层处理
 * 
 * @author alexis
 * @date 2025-09-20
 */
@Service
@Slf4j
public class FamilyMemberServiceImpl extends ServiceImpl<FamilyMemberMapper, FamilyMember> implements IFamilyMemberService {
    /**
     * 微信登录
     *
     * @param dto
     * @return
     */
    @Autowired
    private IWechatService wechatService;
    @Autowired
    private TokenService tokenService;
    @Autowired
    private IElderService elderService;
    @Autowired
    private IFamilyMemberElderService familyMemberElderService;
    @Autowired
    private FamilyMemberMapper familyMemberMapper;
    @Autowired
    private IDeviceService deviceService;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private DeviceDataMapper deviceDataMapper;
    @Autowired
    private IoTDAClient client;

    static List<String> DEFAULT_NICKNAME_PREFIX = ListUtil.of("生活更美好",
            "大桔大利",
            "日富一日",
            "好柿开花",
            "柿柿如意",
            "一椰暴富",
            "大柚所为",
            "杨梅吐气",
            "天生荔枝"
    );

    @Override
    @Transactional(rollbackFor = Exception.class)
    public LoginVo login(UserLoginRequestDto dto) {
        //1.根据code调用微信api获取openId
        String openid = wechatService.getOpenid(dto.getCode());
        //2.根据openId查询数据库获取用户信息family_member表
        //sql:select * from family_member where openId=?
        FamilyMember member = lambdaQuery().eq(FamilyMember::getOpenId, openid).one();
        //3.判断用户信息是否存在，如果不存在，则准备新增，设置openid
        if (member == null) {
            member = new FamilyMember();
            String nickName = DEFAULT_NICKNAME_PREFIX.get((int) (Math.random() * DEFAULT_NICKNAME_PREFIX.size()))
                    + StringUtils.substring(member.getPhone(), 7);
            member.setName(nickName);
            member.setOpenId(openid);
        }
        //4.调用微信api获取用户绑定手机号
        String phone = wechatService.getPhone(dto.getPhoneCode());
        member.setPhone(phone);
        //5.新增或者修改family_member表数据
        saveOrUpdate(member);
        //6.将用户id存入token中，并返回数据给前端
        LoginVo vo = new LoginVo();
        vo.setNickName(member.getName());
        Map<String, Object> map = new HashMap<>();
        map.put("userId", member.getId());
        map.put("nickName", member.getName());
        String token = tokenService.createToken(map);
        vo.setToken(token);
        return vo;
    }

    /**
     * 小程序端绑定老人
     *
     * @param dto
     */
    @Override
    public void bindELder(BindElderDto dto) {
        //判断是否存在该老人
        Elder elder = elderService.lambdaQuery()
                .eq(Elder::getIdCardNo, dto.getIdCard())
                .eq(Elder::getName, dto.getName())
                .one();
        if (ObjectUtil.isEmpty(elder)) {
            throw new RuntimeException("该老人不存在");
        }
        //从threadlocal中拿到当前用户id
        Long id = UserThreadLocal.get();
        //搬砖开始
        FamilyMemberElder familyMemberElder = new FamilyMemberElder();
        familyMemberElder.setFamilyMemberId(id);
        familyMemberElder.setElderId(elder.getId());
        familyMemberElder.setRemark(dto.getRemark());
        familyMemberElderService.save(familyMemberElder);
        //搬砖结束
    }

    /**
     * 查询家人列表
     *
     * @return
     */
    @Override
    public List<BindElderVo> getall() {
        //从threadlocal中拿到当前用户id(重业务,轻sql)
        Long id = UserThreadLocal.get();
        List<BindElderVo> bindElderVos = new ArrayList<>();
        List<FamilyMemberElder> familyMemberElderList = familyMemberElderService.lambdaQuery().eq(FamilyMemberElder::getFamilyMemberId, id).list();
        for (FamilyMemberElder list : familyMemberElderList) {
            BindElderVo bindElderVo = BeanUtil.toBean(list, BindElderVo.class);//深拷贝进vo里
            Elder elder = elderService.lambdaQuery().eq(Elder::getId, list.getElderId()).one();//查询老人姓名
            bindElderVo.setElderName(elder.getName());//添加老人姓名
            bindElderVos.add(bindElderVo);//将获得每个家属信息添加到vo里
        }
        return bindElderVos;
    }

    /**
     * 分页绑定家人
     *
     * @return
     */
    @Override
    public List<PageVo> pageList() {
        //从threadlocal中拿到当前用户id
        Long id = UserThreadLocal.get();
        return familyMemberMapper.pageList(id);//仅查询当前用户绑定的数据
    }

    /**
     * 查询健康数据
     *
     * @param dto
     * @return
     */
    @Override
    public DeviceStatusDataVO queryDeviceProperty(QueryDevicePropertyStatusDto dto) {
        //1.先从数据库拿iotid,用设备名称拿就行,之前接口已经效验过设备名称是唯一的
        Device device = deviceService.lambdaQuery().eq(Device::getDeviceName, dto.getDeviceName()).one();
        if (ObjectUtil.isEmpty(device)) {
            throw new RuntimeException("该设备不存在");
        }
        //2.凭借iotid从redis中拿到设备的最新数据
        String cache = (String) redisTemplate.opsForHash().get(Constants.IOT_DEVICE_LAST_DATA, device.getIotId());
        if (StrUtil.isEmpty(cache)) {
            throw new RuntimeException("获取该设备最新信息失败");
        }
        //3.拿到之后赋值给vo;
        List<DeviceData> list = JSONUtil.toList(cache, DeviceData.class);
        DeviceStatusDataVO vo = new DeviceStatusDataVO();
        DeviceStatusListVO vo1 = new DeviceStatusListVO();
        vo.setList(vo1);
        vo1.setPropertyStatusInfo(new ArrayList<>());
        List<PropertyStatusInfoVO> volist = vo.getList().getPropertyStatusInfo();//预防空指针!!!
        //感觉写麻烦了,不知道用map写会不会好一点
        for (DeviceData deviceData : list) {
            PropertyStatusInfoVO info = new PropertyStatusInfoVO();
            //开始搬砖
            info.setIdentifier(deviceData.getFunctionId());
            long timestamp = deviceData.getAlarmTime().toInstant(ZoneOffset.ofHours(8)).toEpochMilli();
            //将带T的是时间格式转化成毫秒时间戳(由ai生成):这里 ZoneOffset.ofHours(8) 是指定时区为东八区（北京时间），可根据实际需求调整时区
            info.setTime(String.valueOf(timestamp));
            info.setValue(deviceData.getDataValue());
            //改为从华为云拿数据:
            ShowProductRequest request = new ShowProductRequest();
            request.withProductId(dto.getProductKey());
            ShowProductResponse response = client.showProduct(request);
            //对拿到的数据进行解析:
            List<ServiceCapability> list1 = response.getServiceCapabilities();
            List<ServiceProperty> properties = list1.get(0).getProperties();
            //对集合进行遍历
            for (ServiceProperty property : properties) {
                if(!info.getIdentifier().equals(property.getPropertyName())){
                    continue;
                }
                //代码写到这,就相等了,开始搬砖
                info.setDataType(property.getDataType());//赋值数据类型
                info.setUnit(property.getUnit());//赋值单位
                info.setName(property.getDescription());//赋值中文功能名称
            }
            //对name字段和unit字段进行效验,感觉还是写的太麻烦了
//            if ("HeartRate".equals(deviceData.getFunctionId())) {
//                info.setName("心率");
//                info.setUnit("");
//            } else if ("BodyTemp".equals(deviceData.getFunctionId())) {
//                info.setName("体温");
//                info.setUnit(".C");
//            } else if ("xueyang".equals(deviceData.getFunctionId())) {
//                info.setName("血氧");
//                info.setUnit("");//接口文档中这个没有设置值,感觉不应该啊
//            } else {
//                info.setName("电池电量百分比");
//                info.setUnit("%");
//            }
            volist.add(info);//将遍历的每条数据加进来
        }
        return vo;
    }

    /**
     * 按小时查询数据
     * @param dto
     * @return
     */
    @Override
    public List<TimeSeriesDataVO> queryDeviceDataListByDay(QueryDeviceDataDto dto) {
        //直接去数据库查询信息,然后将结果封装进来
        //将字符串毫秒值Long类型时间格式数据转换成LocalDatetime东八区时间(ai生成)
        Long startDateTime = dto.getStartTime();//取出开始时间
        Long endDateTime = dto.getEndTime();//取出结束时间
        LocalDateTime startLocalDateTime = LocalDateTime.ofInstant(
                Instant.ofEpochMilli(startDateTime),
                ZoneId.of("Asia/Shanghai") // 或指定时区如ZoneId.of("Asia/Shanghai")
        );//进行转换
        LocalDateTime endLocalDateTime = LocalDateTime.ofInstant(
                Instant.ofEpochMilli(endDateTime),
                ZoneId.of("Asia/Shanghai") // 或指定时区如ZoneId.of("Asia/Shanghai")
        );//进行转换
        //调用mapper方法
        return deviceDataMapper.queryDeviceDataListByDay(dto.getFunctionId(), dto.getIotId(), startLocalDateTime, endLocalDateTime);
    }

    /**
     * 按天查询数据
     * @param dto
     * @return
     */
    @Override
    public List<TimeSeriesDataVO> queryDeviceDataListByWeek(QueryDeviceDataDto dto) {
        Long startDateTime = dto.getStartTime();//取出开始时间
        Long endDateTime = dto.getEndTime();//取出结束时间
        LocalDateTime startLocalDateTime = LocalDateTime.ofInstant(
                Instant.ofEpochMilli(startDateTime),
                ZoneId.of("Asia/Shanghai") // 或指定时区如ZoneId.of("Asia/Shanghai")
        );//进行转换
        LocalDateTime endLocalDateTime = LocalDateTime.ofInstant(
                Instant.ofEpochMilli(endDateTime),
                ZoneId.of("Asia/Shanghai") // 或指定时区如ZoneId.of("Asia/Shanghai")
        );//进行转换
        //调用mapper方法
        return deviceDataMapper.queryDeviceDataListByWeek(dto.getFunctionId(), dto.getIotId(), startLocalDateTime, endLocalDateTime);
    }
}